package com.StarStudio.Controller;

import com.StarStudio.RabbitMQ.MQSender;
import com.StarStudio.Service.PanicBuyingCouponsService;
import com.StarStudio.Service.PanicBuyingGoodsService;
import com.StarStudio.Service.PanicBuyingOrdersService;
import com.StarStudio.Utils.JsonUtil;
import com.StarStudio.Utils.QueryPageUtils;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.core.Entity.*;
import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.system.api.domain.SysUser;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Slf4j
@RestController
@RequestMapping("/pb_orders")
@Api(tags = "抢购订单接口")
public class PanicBuyingOrdersController implements InitializingBean {

    @Autowired
    PanicBuyingOrdersService panicBuyingOrdersService;

    @Autowired
    PanicBuyingGoodsService panicBuyingGoodsService;

    @Autowired
    PanicBuyingCouponsService panicBuyingCouponsService;

    @Autowired
    RedisService redisService;

    @Autowired
    MQSender mqSender;

    private final Map<Long,Boolean> EmptyGoodsStockMap = new HashMap<>(); //商品库存是否为空的标识
    private final Map<Long,Boolean> EmptyCouponsStockMap = new HashMap<>(); //优惠券库存是否为空的标识
    private static final DefaultRedisScript<Boolean> STOCK_SCRIPT; //Lua脚本初始化

    static {
        STOCK_SCRIPT = new DefaultRedisScript<>();
        STOCK_SCRIPT.setLocation(new ClassPathResource("Stock.lua"));
        STOCK_SCRIPT.setResultType(Boolean.class);
    }

    /**
     * 带搜索条件分页查询
     * @param panicBuyingOrders 抢购订单对象
     * @return 结果对象 Result
     */
    @GetMapping("/page/{flag}")
    @ApiOperation("抢购订单分页接口 ->  flag = 0 查询全部，flag = 1，查询商品抢购订单，flag = 2查询优惠券抢购订单。" +
            "支持条件检索，检索条件封装在抢购订单对象PanicBuyingOrders中。如需分页，必传pageNum和pageSize")
    public PageResult findPanicBuyingOrdersList(PanicBuyingOrders panicBuyingOrders,@PathVariable("flag") int flag){
        QueryPageUtils.startPage();
        PageInfo pageInfo;
        List<PanicBuyingOrders> panicBuyingOrdersList;
        long totalRecord;
        try {
            if (flag == 0){ //查询所有记录
                panicBuyingOrdersList = panicBuyingOrdersService.findPanicBuyingOrdersList(panicBuyingOrders);
                SysUser sysUser = SecurityUtils.getLoginUser().getSysUser();
                if (sysUser.isAdmin()){
                    totalRecord = panicBuyingOrdersService.findTotalRecord();
                }else {
                    totalRecord = panicBuyingOrdersService.findStoreTotalRecord(sysUser.getUserId());
                }
                pageInfo = new PageInfo<>(panicBuyingOrdersList);
            } else if (flag == 1) { //查询商品抢购订单
                panicBuyingOrdersList = panicBuyingOrdersService.findPanicBuyingGoodsOrdersList(panicBuyingOrders);
                SysUser sysUser = SecurityUtils.getLoginUser().getSysUser();
                if (sysUser.isAdmin()){
                    totalRecord = panicBuyingOrdersService.findPanicBuyingGoodsOrdersTotalRecord();
                }else {
                    totalRecord = panicBuyingOrdersService.findStorePanicBuyingGoodsOrdersTotalRecord(sysUser.getUserId());
                }
                pageInfo = new PageInfo<>(panicBuyingOrdersList);
            } else if (flag == 2) { //查询优惠券抢购订单
                panicBuyingOrdersList = panicBuyingOrdersService.findPanicBuyingCouponsOrdersList(panicBuyingOrders);
                SysUser sysUser = SecurityUtils.getLoginUser().getSysUser();
                if (sysUser.isAdmin()){
                    totalRecord = panicBuyingOrdersService.findPanicBuyingCouponsOrdersTotalRecord();
                }else {
                    totalRecord = panicBuyingOrdersService.findStorePanicBuyingCouponsOrdersTotalRecord(sysUser.getUserId());
                }
                pageInfo = new PageInfo<>(panicBuyingOrdersList);
            }else {
                return new PageResult(HttpStatusCode.BAD_REQUEST,MessageConstant.NOT_NULL_PARAMETER_ERROR);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return new PageResult(HttpStatusCode.ERROR, MessageConstant.QUERY_PANIC_BUYING_ORDERS_FAIL);
        }
        return new PageResult(HttpStatusCode.SUCCESS,MessageConstant.QUERY_PANIC_BUYING_ORDERS_SUCCESS,pageInfo.getTotal(),panicBuyingOrdersList,totalRecord);
    }

    /**
     *  抢购接口
     * @param orders 订单对象
     * @return 结果对象 Result
     */
    @PostMapping
    @ApiOperation("抢购接口 -> 如果抢购实体商品，则优惠券ID设为null，反之亦然")
    public Result NewPanicBuyingOrders(@RequestBody Orders orders){
        if (orders.getOrder_user_id() == null || orders.getStore_id() == null || orders.getOrder_status() == null
            || orders.getConsignee_name() == null || orders.getConsignee_phone() == null ||
            orders.getConsignee_address() == null || (orders.getGoods_id() == null && orders.getCoupons_id() == null)){
            return new Result(HttpStatusCode.BAD_REQUEST,MessageConstant.NOT_NULL_PARAMETER_ERROR);
        }
        orders.setNumber(1);//每个用户只能抢一件
        if (orders.getOrder_user_id() == null){
            return new Result(HttpStatusCode.ERROR,MessageConstant.USER_NO_EXIST);
        }
        if (orders.getGoods_id() != null && orders.getGoods_id() > 0 && orders.getCoupons_id() == null){ /* 实体商品抢购 */
            //判断是否重复抢购
            PanicBuyingOrders panicBuyingOrders = redisService.getCacheObject("panic_buying_goods_order:" + orders.getOrder_user_id() + ":" + orders.getGoods_id());
            if (panicBuyingOrders != null){
                return new Result(HttpStatusCode.ERROR,MessageConstant.ONLY_ONE_GOODS_CAN_BUY_PER_PERSON);
            }
            //通过内存标记减少 Redis访问
            if (EmptyGoodsStockMap.get(orders.getGoods_id())){
                return new Result(HttpStatusCode.ERROR,MessageConstant.OUT_OF_GOODS_STOCK);
            }
            //Redis预减库存
            /*Integer stock = redisService.getCacheObject("panic_buying_goods:" + orders.getGoods_id());
            //Long stock = redisService.decrement("panic_buying_goods:" + orders.getGoods_id());
            if (stock < 1){
                EmptyGoodsStockMap.put(orders.getGoods_id(),true);
                return new Result(HttpStatusCode.ERROR,MessageConstant.OUT_OF_GOODS_STOCK);
            }
            redisService.setCacheObject("panic_buying_goods:" + orders.getGoods_id(), stock - 1);*/
            //执行Lua脚本  保证原子性
            Boolean res = redisService.execute(STOCK_SCRIPT, Collections.singletonList("panic_buying_goods:"),orders.getGoods_id());
            if (!res){
                EmptyGoodsStockMap.put(orders.getGoods_id(),true);
                return new Result(HttpStatusCode.ERROR,MessageConstant.OUT_OF_GOODS_STOCK);
            }
            //向rabbitmq broker发送数据
            //因为使用了rabbitmq，使得抢购变成异步操作，达到流量削峰的效果  同时可以快速返回信息(如："正在努力抢购中...")给用户  体验较好
            mqSender.sendPanicBuyingMessage(JsonUtil.object2JsonStr(orders));
            return new Result(HttpStatusCode.SUCCESS,MessageConstant.PANIC_BUYING);
        } else if (orders.getCoupons_id() != null && orders.getCoupons_id() > 0 && orders.getGoods_id() == null) { //优惠券抢购
            //判断是否重复抢购
            PanicBuyingOrders panicBuyingOrders = redisService.getCacheObject("panic_buying_coupons_order:" + orders.getOrder_user_id() + ":" + orders.getCoupons_id());
            if (panicBuyingOrders != null){
                return new Result(HttpStatusCode.ERROR,MessageConstant.ONLY_ONE_GOODS_CAN_BUY_PER_PERSON);
            }
            //通过内存标记减少 Redis访问
            if (EmptyCouponsStockMap.get(orders.getCoupons_id())){
                return new Result(HttpStatusCode.ERROR,MessageConstant.OUT_OF_GOODS_STOCK);
            }
            //Redis预减库存
            //Integer stock = redisService.getCacheObject("panic_buying_coupons:" + orders.getCoupons_id());
            /*Long stock = redisService.decrement("panic_buying_coupons:" + orders.getCoupons_id());
            if (stock < 1){
                EmptyCouponsStockMap.put(orders.getCoupons_id(),true);
                return new Result(HttpStatusCode.ERROR,MessageConstant.OUT_OF_COUPONS_STOCK);
            }
            redisService.setCacheObject("panic_buying_coupons:" + orders.getCoupons_id(), stock - 1);*/
            //执行Lua脚本 保证原子性
            Boolean res = redisService.execute(STOCK_SCRIPT, Collections.singletonList("panic_buying_coupons:"),orders.getCoupons_id());
            log.info("----------------------------" + "panic_buying_coupons:"+ orders.getCoupons_id());
            if (!res){
                EmptyCouponsStockMap.put(orders.getCoupons_id(),true);
                return new Result(HttpStatusCode.ERROR,MessageConstant.OUT_OF_COUPONS_STOCK);
            }
            //向rabbitmq broker发送数据
            //因为使用了rabbitmq，使得秒杀变成异步操作，达到流量削峰的效果  同时可以快速返回信息(如："正在努力抢购中...")给用户  体验较好
            mqSender.sendPanicBuyingMessage(JsonUtil.object2JsonStr(orders));
            return new Result(HttpStatusCode.SUCCESS,MessageConstant.PANIC_BUYING);
        }
        return new Result(HttpStatusCode.BAD_REQUEST,MessageConstant.INCORRECT_CLIENT_REQUEST);
    }


    /**
     * 系统初始化时将抢购商品库存加载到 Redis
     */
    @Override
    public void afterPropertiesSet() {
        List<PanicBuyingGoods> panicBuyingGoodsList = panicBuyingGoodsService.PanicBuyingGoodsList();
        if (!CollectionUtils.isEmpty(panicBuyingGoodsList)){
            panicBuyingGoodsList.forEach(panicBuyingGoods -> {
                redisService.setCacheObject("panic_buying_goods:" + panicBuyingGoods.getGoods_id(),panicBuyingGoods.getPanic_buying_goods_stock());
                EmptyGoodsStockMap.put(panicBuyingGoods.getGoods_id(),false);
            });
        }
        List<PanicBuyingCoupons> panicBuyingCouponsList = panicBuyingCouponsService.PanicBuyingCouponsList();
        if (!CollectionUtils.isEmpty(panicBuyingCouponsList)){
            panicBuyingCouponsList.forEach(panicBuyingCoupons -> {
                redisService.setCacheObject("panic_buying_coupons:" + panicBuyingCoupons.getCoupons_id(), panicBuyingCoupons.getPanic_buying_coupons_stock());
                EmptyCouponsStockMap.put(panicBuyingCoupons.getCoupons_id(),false);
            });
        }
    }

    /**
     * 定时任务 每10秒检查一次 Redis中的商品库存数量和优惠券库存数量，判断库存是否已为空
     */
    @Scheduled(cron ="*/10 * * * * ?")
    public void AutoCheckRedisStockStatus(){
        List<Long> goodsIdList = panicBuyingGoodsService.getGoodsIdListFromPanicBuyingGoods();
        if (!CollectionUtils.isEmpty(goodsIdList)){
            for (Long goodsId : goodsIdList) {
                Integer goodsStock = redisService.getCacheObject("panic_buying_goods:" + goodsId);
                if (goodsStock > 0){
                    EmptyGoodsStockMap.put(goodsId,false);
                }
            }
        }
        List<Long> couponsIdList = panicBuyingCouponsService.getCouponsIdListFromPanicBuyingCoupons();
        if (!CollectionUtils.isEmpty(couponsIdList)){
            for (Long couponsId : couponsIdList) {
                Integer couponsStock = redisService.getCacheObject("panic_buying_coupons:" + couponsId);
                if (couponsStock > 0){
                    EmptyCouponsStockMap.put(couponsId,false);
                }
            }
        }
    }

    /**
     * 查询抢购结果 （前端轮询结果）
     * @param user_id 用户ID
     * @param type 抢购商品类型（ 1：实体商品，2：优惠券）
     * @param thingsId 抢购物品对应的商品ID或优惠券ID（注意是实际商品ID，不是记录ID）
     * @return 结果对象 Result
     */
    @GetMapping("/result/{user_id}/{type}/{thingsId}")
    @ApiOperation("查询抢购结果接口 -> path必传用户ID、抢购商品类型（ 1：实体商品，2：优惠券）、抢购物品对应的商品ID或优惠券ID（注意是实际商品ID，不是记录ID）")
    public Result checkPanicBuyingResult(@PathVariable long user_id,@PathVariable int type,@PathVariable long thingsId){
        if (type == 1){ //实体商品
            if (redisService.hasKey("panic_buying_goods_order:" + user_id + ":" + thingsId)){ //Redis中有键，抢购成功
                PanicBuyingOrders panicBuyingOrder = redisService.getCacheObject("panic_buying_goods_order:" + user_id + ":" + thingsId);
                if (panicBuyingOrder != null){
                    return new Result(HttpStatusCode.SUCCESS,MessageConstant.PANIC_BUYING_GOODS_SUCCESS,panicBuyingOrder.getOrder_id());
                }
            }else {
                if (EmptyGoodsStockMap.getOrDefault(thingsId,true)){
                    return new Result(HttpStatusCode.ERROR,MessageConstant.PANIC_BUYING_FAIL);
                }
                return new Result(HttpStatusCode.CONTINUE,MessageConstant.PANIC_BUYING);
            }
            return new Result(HttpStatusCode.ERROR,MessageConstant.PANIC_BUYING_FAIL);
        }else if (type == 2){
            if (redisService.hasKey("panic_buying_coupons_order:" + user_id + ":" + thingsId)){ //Redis中有键，抢购成功
                PanicBuyingOrders panicBuyingOrder = redisService.getCacheObject("panic_buying_coupons_order:" + user_id + ":" + thingsId);
                if (panicBuyingOrder != null){
                    return new Result(HttpStatusCode.SUCCESS,MessageConstant.PANIC_BUYING_COUPONS_SUCCESS,panicBuyingOrder.getOrder_id());
                }
            }else {
                if (EmptyCouponsStockMap.getOrDefault(thingsId,true)){
                    return new Result(HttpStatusCode.ERROR,MessageConstant.PANIC_BUYING_FAIL);
                }
                return new Result(HttpStatusCode.CONTINUE,MessageConstant.PANIC_BUYING);
            }
            return new Result(HttpStatusCode.ERROR,MessageConstant.PANIC_BUYING_FAIL);
        }else {
            return new Result(HttpStatusCode.BAD_REQUEST,MessageConstant.INCORRECT_CLIENT_REQUEST);
        }
    }

//
//    /**
//     * 获取抢购路径
//     * @param user 用户对象
//     * @param goods_id 商品ID
//     * @param captcha 验证码
//     * @return 结果对象
//     */
//    @GetMapping("/path")
//    @ResponseBody
//    public Result getPath(User user, Long goods_id, String captcha, HttpServletRequest request){
//        if (user == null){
//            return new Result(HttpStatusCode.ERROR,MessageConstant.USER_NOT_FOUND);
//        }
//        ValueOperations<String, Object> operations = redisTemplate.opsForValue();
//        //限制访问次数，5秒内访问5次
//        String uri = request.getRequestURI();
//        captcha = "0";
//        Integer count = (Integer) operations.get(uri + ":" + user.getUser_id());
//        if (count == null){
//            operations.set(uri + ":" + user.getUser_id(),1,5,TimeUnit.SECONDS);
//        } else if (count < 5) {
//            operations.increment(uri + ":" + user.getUser_id());
//        }else {
//            return new Result(HttpStatusCode.WARNING,MessageConstant.ACCESS_LIMIT);
//        }
//        boolean checkCaptcha = orderService.checkCaptcha(user,goods_id,captcha);
//        if (!checkCaptcha){
//            return new Result(HttpStatusCode.ERROR,MessageConstant.CAPTCHA_INCORRECT);
//        }
//        String str = orderService.createPath(user,goods_id);
//        return new Result(HttpStatusCode.SUCCESS,MessageConstant.GET_PATH_SUCCESS,str);
//    }
//
//    /**
//     * 生成验证码
//     * @param user 用户对象
//     * @param goods_id 商品ID
//     * @param response HTTP响应
//     */
//    @GetMapping("/captcha")
//    public void checkCode(User user, Long goods_id, HttpServletResponse response){
//        if (user == null || goods_id < 0){
//            throw new GlobalException(new Result(HttpStatusCode.ERROR,MessageConstant.ILLEGAL_REQUEST));
//        }
//        //设置请求头为输出图片的类型
//        response.setContentType("image/jpg");
//        response.setHeader("Pargam","No-cache");
//        response.setHeader("Cache-Control","no-cache");
//        response.setDateHeader("Expires",0);
//        //生成验证码
//        ArithmeticCaptcha captcha = new ArithmeticCaptcha(130, 32, 3);
//        redisTemplate.opsForValue().set("captcha" + user.getUser_id() + ":" + goods_id, captcha.text(),300, TimeUnit.SECONDS);
//        try {
//            captcha.out(response.getOutputStream());
//        } catch (IOException e) {
//            e.printStackTrace();
//            log.error(MessageConstant.GENERATE_CAPTCHA_FAIL,e.getMessage());
//        }
//    }
}


